"""
页面管理器
管理数据页面的分配、回收和记录操作
"""

import struct
from typing import List, Dict, Any, Optional, Tuple
from .buffer_manager import BufferManager
from .storage_manager import StorageManager

class Record:
    """记录类"""
    
    def __init__(self, data: Dict[str, Any], schema: Dict[str, Any]):
        """初始化记录"""
        self.data = data
        self.schema = schema
        self.record_id = None  # 记录ID（页面内偏移）
    
    def serialize(self) -> bytearray:
        """序列化记录为字节数组"""
        data_bytes = bytearray()
        
        for col_name, col_def in self.schema['columns'].items():
            value = self.data.get(col_name)
            
            if value is None:
                # NULL值用特殊标记表示
                data_bytes.extend(b'\xFF\xFF\xFF\xFF')
            else:
                data_type = col_def['type']
                if data_type['type'] == 'int':
                    data_bytes.extend(struct.pack('<i', int(value)))
                elif data_type['type'] == 'float':
                    data_bytes.extend(struct.pack('<f', float(value)))
                elif data_type['type'] == 'boolean':
                    data_bytes.extend(struct.pack('<?', bool(value)))
                elif data_type['type'] == 'varchar':
                    # 变长字符串：长度(4字节) + 数据
                    str_value = str(value)
                    str_bytes = str_value.encode('utf-8')
                    data_bytes.extend(struct.pack('<I', len(str_bytes)))
                    data_bytes.extend(str_bytes)
        
        return data_bytes
    
    @classmethod
    def deserialize(cls, data: bytearray, schema: Dict[str, Any], offset: int = 0) -> Tuple['Record', int]:
        """从字节数组反序列化记录"""
        record_data = {}
        pos = offset
        
        for col_name, col_def in schema['columns'].items():
            data_type = col_def['type']
            
            if data_type['type'] == 'int':
                value = struct.unpack('<i', data[pos:pos+4])[0]
                pos += 4
            elif data_type['type'] == 'float':
                value = struct.unpack('<f', data[pos:pos+4])[0]
                pos += 4
            elif data_type['type'] == 'boolean':
                value = struct.unpack('<?', data[pos:pos+1])[0]
                pos += 1
            elif data_type['type'] == 'varchar':
                # 检查是否为NULL
                if data[pos:pos+4] == b'\xFF\xFF\xFF\xFF':
                    value = None
                    pos += 4
                else:
                    length = struct.unpack('<I', data[pos:pos+4])[0]
                    pos += 4
                    value = data[pos:pos+length].decode('utf-8')
                    pos += length
            
            record_data[col_name] = value
        
        record = cls(record_data, schema)
        return record, pos

class PageManager:
    """页面管理器"""
    
    def __init__(self, storage_manager: StorageManager, buffer_manager: BufferManager):
        """初始化页面管理器"""
        self.storage_manager = storage_manager
        self.buffer_manager = buffer_manager
        self.page_size = storage_manager.page_size
        self.page_header_size = 12  # 页面头部大小
    
    def insert_record(self, table_name: str, record: Record) -> bool:
        """插入记录"""
        schema = self.storage_manager.get_schema(table_name)
        if not schema:
            raise Exception(f"表 '{table_name}' 不存在")
        
        # 序列化记录
        record_bytes = record.serialize()
        record_size = len(record_bytes)
        
        # 查找有足够空间的页面
        page_id = self._find_free_page(table_name, record_size)
        if page_id is None:
            # 分配新页面
            page_id = self.storage_manager.allocate_page(table_name)
        
        # 读取页面
        page_data = self.buffer_manager.get_page(table_name, page_id)
        if not page_data:
            raise Exception(f"无法读取页面 {page_id}")
        
        # 在页面中插入记录
        success = self._insert_record_in_page(page_data, record_bytes, record)
        if success:
            # 标记页面为脏页
            self.buffer_manager.mark_dirty(table_name, page_id)
            # 更新记录计数
            self.storage_manager.update_record_count(table_name, 1)
            return True
        
        return False
    
    def delete_record(self, table_name: str, page_id: int, record_id: int) -> bool:
        """删除记录"""
        page_data = self.buffer_manager.get_page(table_name, page_id)
        if not page_data:
            return False
        
        # 从页面中删除记录
        success = self._delete_record_in_page(page_data, record_id)
        if success:
            self.buffer_manager.mark_dirty(table_name, page_id)
            self.storage_manager.update_record_count(table_name, -1)
            return True
        
        return False
    
    def update_record(self, table_name: str, page_id: int, record_id: int, new_data: Dict[str, Any]) -> bool:
        """更新记录"""
        schema = self.storage_manager.get_schema(table_name)
        if not schema:
            return False
        
        page_data = self.buffer_manager.get_page(table_name, page_id)
        if not page_data:
            return False
        
        # 读取原记录
        old_record, _ = Record.deserialize(page_data, schema, record_id)
        
        # 创建新记录
        new_record = Record(new_data, schema)
        
        # 序列化新记录
        new_record_bytes = new_record.serialize()
        
        # 检查大小是否匹配
        if len(new_record_bytes) != len(old_record.serialize()):
            # 大小不匹配，需要删除旧记录并插入新记录
            self._delete_record_in_page(page_data, record_id)
            return self._insert_record_in_page(page_data, new_record_bytes, new_record)
        else:
            # 大小匹配，直接替换
            page_data[record_id:record_id + len(new_record_bytes)] = new_record_bytes
            self.buffer_manager.mark_dirty(table_name, page_id)
            return True
    
    def scan_records(self, table_name: str) -> List[Tuple[int, int, Record]]:
        """扫描所有记录"""
        schema = self.storage_manager.get_schema(table_name)
        if not schema:
            return []
        
        records = []
        page_count = self.storage_manager.get_page_count(table_name)
        
        for page_id in range(page_count):
            page_data = self.buffer_manager.get_page(table_name, page_id)
            if page_data:
                page_records = self._scan_page_records(page_data, schema, page_id)
                records.extend(page_records)
        
        return records
    
    def _find_free_page(self, table_name: str, record_size: int) -> Optional[int]:
        """查找有足够空间的页面"""
        page_count = self.storage_manager.get_page_count(table_name)
        
        for page_id in range(page_count):
            page_data = self.buffer_manager.get_page(table_name, page_id)
            if page_data:
                free_space = self._get_page_free_space(page_data)
                if free_space >= record_size:
                    return page_id
        
        return None
    
    def _get_page_free_space(self, page_data: bytearray) -> int:
        """获取页面空闲空间"""
        return struct.unpack('<I', page_data[8:12])[0]
    
    def _set_page_free_space(self, page_data: bytearray, free_space: int):
        """设置页面空闲空间"""
        struct.pack_into('<I', page_data, 8, free_space)
    
    def _get_page_record_count(self, page_data: bytearray) -> int:
        """获取页面记录数"""
        return struct.unpack('<I', page_data[4:8])[0]
    
    def _set_page_record_count(self, page_data: bytearray, count: int):
        """设置页面记录数"""
        struct.pack_into('<I', page_data, 4, count)
    
    def _insert_record_in_page(self, page_data: bytearray, record_bytes: bytearray, record: Record) -> bool:
        """在页面中插入记录"""
        free_space = self._get_page_free_space(page_data)
        record_size = len(record_bytes)
        
        if free_space < record_size:
            return False
        
        # 找到插入位置（页面末尾）
        record_count = self._get_page_record_count(page_data)
        
        # 简化实现：将记录追加到页面末尾
        insert_pos = self.page_size - free_space
        
        # 确保有足够空间
        if insert_pos + record_size > self.page_size:
            return False
        
        # 插入记录
        page_data[insert_pos:insert_pos + record_size] = record_bytes
        
        # 更新页面头部
        self._set_page_record_count(page_data, record_count + 1)
        self._set_page_free_space(page_data, free_space - record_size)
        
        # 设置记录ID
        record.record_id = insert_pos
        
        return True
    
    def _delete_record_in_page(self, page_data: bytearray, record_id: int) -> bool:
        """从页面中删除记录"""
        record_count = self._get_page_record_count(page_data)
        if record_count == 0:
            return False
        
        # 简化实现：将记录标记为删除（用特殊值填充）
        # 实际实现中可能需要更复杂的逻辑来处理碎片整理
        page_data[record_id:record_id + 4] = b'\xFF\xFF\xFF\xFF'  # 标记为删除
        
        # 更新记录计数
        self._set_page_record_count(page_data, record_count - 1)
        
        return True
    
    def _scan_page_records(self, page_data: bytearray, schema: Dict[str, Any], page_id: int) -> List[Tuple[int, int, Record]]:
        """扫描页面中的记录"""
        records = []
        record_count = self._get_page_record_count(page_data)
        
        if record_count == 0:
            return records
        
        # 简化实现：假设记录是连续存储的，从页面头部开始
        pos = self.page_header_size
        
        for i in range(record_count):
            if pos >= len(page_data):
                break
                
            # 检查记录是否被删除（检查第一个字段是否为删除标记）
            if pos + 4 <= len(page_data) and page_data[pos:pos + 4] == b'\xFF\xFF\xFF\xFF':
                # 跳过删除的记录，尝试找到下一个记录
                pos += 4
                continue
            
            try:
                record, new_pos = Record.deserialize(page_data, schema, pos)
                record.record_id = pos
                records.append((page_id, pos, record))
                pos = new_pos
            except Exception as e:
                print(f"反序列化记录失败: {e}")
                # 如果反序列化失败，尝试跳过一些字节
                pos += 4
                continue
        
        return records

# 测试函数
if __name__ == "__main__":
    from storage_manager import StorageManager
    from buffer_manager import BufferManager
    
    # 创建管理器
    storage = StorageManager("test_data")
    buffer_manager = BufferManager(10)
    buffer_manager.set_storage_manager(storage)
    page_manager = PageManager(storage, buffer_manager)
    
    # 创建测试表
    schema = {
        'columns': {
            'id': {'type': {'type': 'int'}},
            'name': {'type': {'type': 'varchar', 'length': 50}},
            'age': {'type': {'type': 'int'}}
        },
        'primary_key': 'id'
    }
    
    storage.create_table("users", schema)
    
    # 测试插入记录
    print("测试插入记录...")
    record1 = Record({'id': 1, 'name': 'Alice', 'age': 25}, schema)
    record2 = Record({'id': 2, 'name': 'Bob', 'age': 30}, schema)
    
    page_manager.insert_record("users", record1)
    page_manager.insert_record("users", record2)
    
    # 测试扫描记录
    print("扫描记录...")
    records = page_manager.scan_records("users")
    for page_id, record_id, record in records:
        print(f"  页面{page_id}, 记录{record_id}: {record.data}")
    
    # 测试更新记录
    print("测试更新记录...")
    if records:
        page_id, record_id, old_record = records[0]
        new_data = old_record.data.copy()
        new_data['age'] = 26
        page_manager.update_record("users", page_id, record_id, new_data)
    
    # 再次扫描
    print("更新后的记录...")
    records = page_manager.scan_records("users")
    for page_id, record_id, record in records:
        print(f"  页面{page_id}, 记录{record_id}: {record.data}")
    
    # 清理
    storage.drop_table("users")
    buffer_manager.clear()
